(** JVM bytecode generator implementation in ocaml for the haxe compiler.

 Creates Ocaml intermediate representation of jvm class file reflecting
 haxe features ( 'jvm_type.ml' ).

 Creates Ocaml representation of a jvm class file ( 'jvm_bytecode.ml' ).
 
 Creates binary file from final representation ( 'jvm_classfile.ml and / or jvm_jar.ml' ).

 Wishlist: automatic extern generator for libraries given by user or even 
 better , read in jar or class files and transform to haXe AST ,like
 normal compilers do...
                                        
 @author Oliver Jan Krylow 2010 *)

open Ast_printer
open Type_printer
open Common_printer
open Ast
open Type
open Common

let report_error msg pos =
	print_endline ( "[HaXeJvm ERROR] " ^ msg ^ " . " ^ pos.pfile ^ " , [" ^ string_of_int(pos.pmin) ^ " , " ^ string_of_int(pos.pmax) ^ "] ." )

let report_warning msg pos =
	print_endline ( "[HaXeJvm WARNING] " ^ msg ^ " . " ^ pos.pfile ^ " , [" ^ string_of_int(pos.pmin) ^ " , " ^ string_of_int(pos.pmax) ^ "] ." )

let do_if_verbose jctx proc arg =
	if jctx.verbose then proc arg else ()

exception StillNotYetImplemented

let generate_hx_class jctx clazz = Jvm_type.as_class jctx.debug clazz

let generate_hx_interface jctx interface = Jvm_type.as_interface jctx.debug interface

let generate_hx_enum jctx enum = Jvm_type.as_enum jctx.debug enum

(** Steps to compile class/interface: send haXe AST to jvm_type to    )
 convert into more jvm specific representation. send jvm representation  
 to jvm_bytecode to convert to class file. send class file to jvm_io to  
 convert to binary buffer. save binary buffer to file named after        
 class/interface and dir according to package structure                  *)
let generate com =
	
	print_ctx com;
	
	let convert_to_constructs types =
		(match types with
					| TClassDecl cla when not cla.cl_extern -> (* types that need to be compiled *)
					
						(*	print_endline "" ;
							print_endline "\n--------------------------------";
							
							print_class cla;*)
							
							if cla.cl_interface
							then generate_hx_interface com cla
							else generate_hx_class com cla
					
					| TEnumDecl enum when not enum.e_extern ->
							
						(*	print_endline "" ;
							print_endline "\n--------------------------------";*)
							
							generate_hx_enum com enum
					
					| TClassDecl ext_cla ->
					
							(*print_endline "" ;
							print_string "EXTERN :   ";
							print_path ext_cla.cl_path;*)
							print_endline "\n--------------------------------";
							[]
					(* some extern classes that need to be mapped to jvm   *)
					(* specific types ?                                    *)
					| TEnumDecl ext_enum ->
					
							(*print_endline "" ;
							print_string "EXTERN :   ";
							print_path ext_enum.e_path;*)
							print_endline "\n--------------------------------";
							[]
					
					| TTypeDecl def ->  (* TODO:explore find out why this case is ignorable *)
						(*print_endline "" ;
						print_endline "\n--------------------------------";
						print_def def;*)
						
						
						[] )
	
	(* We transform every type, meaning class, interface or typedef, from the users code*)
	(* to 'Jvm_type.jvm_constructs', in order to bring them closer to something a Jvm can read. *)
	in let constructs = List.map convert_to_constructs com.types
	
	(* Every construct corresponds to one HaXe class, or interface...*)
	(* But a single construct can be comprised of many 'Jvm_class', 'Jvm_interface' ... elements*)
	(* Here, we create a classfile data structure for every such element, and pass also the*)
	(* version along, that we wish our resulting class file should conform to.*)
	(* For now, only version 1.6 is possible, but in the near future we will have the pleasure to*)
	(* deal with 1.7 and its 'invokeDynamic' magic. *)
	in let classfiles_list =
		List.map
		(fun con -> (Jvm_bytecode.as_classfiles con 1.6))
		constructs
	in
	(* Here we write the classfile data structure to an actual file, or set of files on the *)
	(* users hard drive.*)
	(* Since 'classfiles_list' is a list of list of classfile, we need nested iteration, to retrieve*)
	(* every single classfile. This is comparable to a nested for loop , accessing all elements of *)
	(* a two-dimensional array...*)
	(* TODO:jar determine wther to create a single jar, or a class file dir structure based on*)
	(* the users input after the '-jvm' switch *)
	
	Jvm_io.create_dir com.file ;
	
	List.iter
		(fun classfiles -> 
			List.iter 
			(fun classfile -> Jvm_io.write_bytecode com.file classfile)
			classfiles)
		classfiles_list;
	
	
	report_error "A testy error!" {pfile = "SomeFile.hx"; pmin = 0; pmax = 1};
	report_warning "A testy warning!" {pfile = "SomeFile.hx"; pmin = 0; pmax = 1};
	
	print_endline "DONE!";
